﻿using System;
using System.IO;
using System.Security.Cryptography;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;

public class FileHelper
{
    // 把所有有效文件copy到目标路径
    public static void CopyFiles2TargetDirRecursive(
        string src,
        string dst,
        Func<string, bool> filter = null,
        Func<string, string> nameProcesser = null,
        Func<string, string, bool> opAsset = null)
    {
        Debug.Log(src);
        Debug.Log(dst);

        src = src.Replace("\\", "/");

        DirectoryInfo dir = new DirectoryInfo(src);
        FileSystemInfo[] fis = dir.GetFileSystemInfos();
        foreach (FileSystemInfo fi in fis)
        {
            string destFile = dst + "\\" + fi.Name;
            if (Application.platform == RuntimePlatform.OSXEditor)
            {
                destFile = dst + "/" + fi.Name;
            }

            if (fi is DirectoryInfo)
            {
                if (!Directory.Exists(destFile))
                {
                    Directory.CreateDirectory(destFile);
                }

                CopyFiles2TargetDirRecursive(fi.FullName, destFile, filter, nameProcesser, opAsset);
            }
            else
            {
                if (filter != null && !filter(fi.FullName))
                {
                    continue;
                }

                if (nameProcesser != null)
                {
                    destFile = nameProcesser(destFile);
                }

                // copy资源
                Action<string, string> cpAsset = (srcPath, dstPath) =>
                {
                    if (File.Exists(dstPath))
                        File.Copy(srcPath, dstPath, true);
                    else
                        File.Copy(srcPath, dstPath);
                };

                if (opAsset == null)
                {
                    cpAsset(fi.FullName, destFile);
                }
                else
                {
                    bool needCopy = opAsset(fi.FullName, destFile);
                    if (needCopy)
                        cpAsset(fi.FullName, destFile);
                }
            }
        }
    }
    
    // 计算文件的MD5值
    public static byte[] CalculateFileMD5(string filePath)
    {
        byte[] name = System.Text.Encoding.Default.GetBytes(filePath + "_");
        byte[] fileMD5 = CreateFileMD5(filePath);
        byte[] metaMD5 = CreateMetaMD5(filePath);

        byte[] bytes = metaMD5 != null
            ? new byte[name.Length + fileMD5.Length + metaMD5.Length]
            : new byte[name.Length + fileMD5.Length];
        Buffer.BlockCopy(name, 0, bytes, 0, name.Length);
        Buffer.BlockCopy(fileMD5, 0, bytes, name.Length, fileMD5.Length);

        if (metaMD5 != null)
        {
            Buffer.BlockCopy(metaMD5, 0, bytes, name.Length + fileMD5.Length, metaMD5.Length);
        }

        return bytes;
    }

    // 创建文件md5值
    public static byte[] CreateFileMD5(string filePath)
    {
        if (!File.Exists(filePath))
        {
            Exception noFileException = new Exception(string.Format("{0} file to get md5 is no exist.", filePath));
            throw noFileException;
        }

        MD5 md5 = MD5.Create();
        using (FileStream fs = File.OpenRead(filePath))
        {
            return md5.ComputeHash(fs);
        }
    }

    // 生成Meta文件的MD5值
    private static byte[] CreateMetaMD5(string filePath)
    {
        string metaName = filePath + ".meta";
        if (!File.Exists(metaName))
        {
            return null;
        }

        MD5 md5 = MD5.Create();
        string pattern = @"timeCreated:\s\d+";
        string replace = @"timeCreated: 0000000000";

        using (StreamReader sr = new StreamReader(metaName))
        {
            string content = sr.ReadToEnd();
            content = System.Text.RegularExpressions.Regex.Replace(content, pattern, replace);

            return md5.ComputeHash(System.Text.Encoding.Default.GetBytes(content));
        }
    }
    
    // patch 路径
    public static string hotfixFolder
    {
        get { return Application.persistentDataPath + "/patch"; }
    }
        
    // streamingassets 路径
    public static string streamingFolder
    {
        get { return Application.streamingAssetsPath; }
    }
    
    public static string checksumHotfixeFile
    {
        get { return $"assets/{checksumName}.ab"; }
    }
    
    public static string checksumFile
    {
        get { return $"assets/{checksumName}"; }
    }
    
    public static string checksumName
    {
        get { return "checksum.asset"; }
    }

    public static string targetPlatform
    {
        get
        {
            string platform = "";
            
#if UNITY_ANDROID
            platform = "Android";
#elif UNITY_IPHONE
            platform = "iOS";
#else
            platform = "StandaloneWindows";
#endif
            return platform;
        }
    }
    
    //patch 上的 manifest 文件路径
    public static string hotfixAssetbundleManifestPath
    {
        get
        {
            return $"{hotfixFolder}/{targetPlatform}";
        }
    }

    public static void DeletDir(string dir, bool recursive = true)
    {
        try
        {
            Directory.Delete(dir, recursive);
        }
        catch (Exception e)
        {
            Debug.Log($"[FileHelper] DeletDir delet dir error, error: {e.Message}");
        }
    }
    
    public static void CreateDirIfNotExist(string dir)
    {
        if (!Directory.Exists(dir))
        {
            Directory.CreateDirectory(dir);
        }
    }
    
    public static async UniTask<DownloadHandler> LoadRemoteHandler(string url, int timeout = 10)
    {
        UnityWebRequest request = new UnityWebRequest(url, UnityWebRequest.kHttpVerbGET, new DownloadHandlerBuffer(), null);
        request.timeout = timeout;
        await request.SendWebRequest();

        while (!request.isDone)
        {
            await UniTask.DelayFrame(1);
        }

        if (request.result != UnityWebRequest.Result.Success)
        {
            return null;
        }
        return request.downloadHandler;
    }
}